package com.tcs.gamed.client;

import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.gwt.user.client.ui.Widget;
import com.tcs.gamed.client.service.FolderService;
import com.tcs.gamed.client.service.FolderServiceAsync;
import com.tcs.gamed.shared.model.FolderItem;

public class FolderList extends Composite {

    private static final ImageListUiBinder uiBinder
        = GWT.create(ImageListUiBinder.class);
    
    private static FolderServiceAsync folderService
        = GWT.create(FolderService.class);
    
    interface ImageListUiBinder extends UiBinder<Widget, FolderList> {
    }
    
    @UiField MenuBar menu;
    @UiField MenuItem uploadImageMenuItem;
    @UiField MenuItem makeFolderMenuItem;
    @UiField MenuItem editMenuItem;
    @UiField Tree folderTree;
    
    private MakeFolderDialog makeFolderDialog = MakeFolderDialog.createMakeFolderDialog();
    private MakeFolderDialog editFolderDialog = MakeFolderDialog.createEditFolderDialog();
    
    public FolderList() {
        initWidget(uiBinder.createAndBindUi(this));
        
        // set up dialog for making folder.
        makeFolderDialog.addCloseHandler(new CloseHandler<PopupPanel>() {
            public void onClose(CloseEvent<PopupPanel> event) {
                onCloseMakeFolderDialog();
            }
        });
        
        editFolderDialog.addCloseHandler(new CloseHandler<PopupPanel>() {
            public void onClose(CloseEvent<PopupPanel> event) {
                onCloseEditFolderDialog();
            }
        });
        
        // set up tree events.
        folderTree.addOpenHandler(new OpenHandler<TreeItem>() {
            public void onOpen(OpenEvent<TreeItem> event) {
                onOpenFolder(event.getTarget());
            }
        });
        folderTree.addCloseHandler(new CloseHandler<TreeItem>() {
            public void onClose(CloseEvent<TreeItem> event) {
                onCloseFolder(event.getTarget());
            }
        });
        folderTree.addSelectionHandler(new SelectionHandler<TreeItem>() {
            public void onSelection(SelectionEvent<TreeItem> event) {
                onSelectionItem(event.getSelectedItem());
            }
        });
        
        // set up menus.
        uploadImageMenuItem.setCommand(new Command() {
            public void execute() {new FileUploadDialog().show();}
        });        
        makeFolderMenuItem.setCommand(new Command() {
            public void execute() {showMakeFolderDialog();}
        });
        editMenuItem.setCommand(new Command() {
            public void execute() {showEditFolderDialog();}
        });
        
        updateAll();
    }
    
    private void updateAll() {
        folderTree.clear();
        loadFolderItems(null);
    }
    
    private void showMakeFolderDialog() {
        makeFolderDialog.setParentFolder(folderTree.getSelectedItem());
        makeFolderDialog.setFolderName(null);
        makeFolderDialog.setFolderComment(null);
        makeFolderDialog.show();
    }
    
    private void showEditFolderDialog() {
        final TreeItem item = folderTree.getSelectedItem();
        if(item != null) {
            final FolderItem folder = (FolderItem) item.getUserObject();
            editFolderDialog.setFolder(item);
            editFolderDialog.setParentFolder(item.getParentItem());
            editFolderDialog.setFolderName(folder.getName());
            editFolderDialog.setFolderComment(folder.getComment());
            editFolderDialog.show();
        }
    }
    
    private void onCloseMakeFolderDialog() {
        if(!makeFolderDialog.isCanceled()) {
            makeFolder(
                makeFolderDialog.getFolderName(),
                makeFolderDialog.getFolderComment(),
                makeFolderDialog.getParentFolder());
        }
    }
    
    private void onCloseEditFolderDialog() {
        if(!editFolderDialog.isCanceled()) {
            editFolder(
                editFolderDialog.getFolder(),
                editFolderDialog.getFolderName(),
                editFolderDialog.getFolderComment());
        }
    }
    
    private void onOpenFolder(TreeItem item) {
        loadFolderItems(item);
    }
    
    private void onCloseFolder(TreeItem item) {
        final FolderItem folder = (FolderItem) item.getUserObject();
        assert folder != null;
        item.removeItems();
        item.addItem("loading...");
    }
    
    private void onSelectionItem(TreeItem selectedItem) {
    }
    
    private void makeFolder(
            final String name, final String comment, final TreeItem parentItem) {
        final String parentKey = (parentItem != null)
                ? ((FolderItem)parentItem.getUserObject()).getKey() : null;
                
        folderService.makeFolder(name, comment, parentKey, new AsyncCallback<FolderItem>() {
            public void onFailure(Throwable caught) {
                Window.alert(caught.getLocalizedMessage());
            }
            public void onSuccess(FolderItem result) {
                if(parentItem != null) {
                    parentItem.addItem(makeTreeItemFolder(result));
                } else {
                    folderTree.addItem(makeTreeItemFolder(result));
                }
            }
        });
    }
    
    private void editFolder(
            final TreeItem item, final String name, final String comment) {
        final FolderItem folder = (FolderItem)item.getUserObject();
                
        folderService.editFolder(
            folder.getKey(), name, comment, folder.getParentKey(), new AsyncCallback<FolderItem>() {
            public void onFailure(Throwable caught) {
                Window.alert(caught.getLocalizedMessage());
            }
            public void onSuccess(FolderItem result) {
                item.setText(result.getName());
            }
        });
    }
    
    private void loadFolderItems(final TreeItem parent) {
        folderService.getChildren(
            getTreeItemKey(parent),
                new AsyncCallback<List<FolderItem>>() {
                public void onFailure(Throwable caught) {
                    Window.alert(caught.getLocalizedMessage());
                }
                public void onSuccess(List<FolderItem> result) {
                    if(parent == null) {
                        for(FolderItem i : result) {
                            folderTree.addItem(makeTreeItemFolder(i));
                        }
                    } else {
                        parent.removeItems();
                        for(FolderItem i : result) {
                            parent.addItem(makeTreeItemFolder(i));
                        }
                    }
                }
            });
    }
    
    private TreeItem makeTreeItemFolder(FolderItem folder) {
        assert folder != null;
        final TreeItem item = new TreeItem();
        item.setUserObject(folder);
        item.setText(folder.getName());
        item.addItem("loading...");
        return item;
    }
    
    private String getTreeItemKey(TreeItem item) {
        if(item == null) {
            return null;
        } else {
            final FolderItem folder = (FolderItem) item.getUserObject();
            return (folder == null) ? null : folder.getKey();
        }
    }
}
